
import java.util.ArrayList;
import java.util.StringTokenizer;
 


class VMArchitecture{

	public class InvalidInstructionSet extends RuntimeException{
		public InvalidInstructionSet(String message){
			super(message);
		}
	}

	public class MemoryVoilationException extends RuntimeException{
		public MemoryVoilationException(String message){
			super(message);
		}
	}

	private final static int SIZE = 65536;
	private SPRegisters SPReg = new SPRegisters();
	private char[] memory = new char[SIZE];
	private char[] stack = new char[60];
	private int[] GPReg = new int[16];
	boolean initialized = false;
	private int COUNTER = 0;


	void initialize(ArrayList<Character> arr){

		SPReg.code.base = 0;


		char ch, ch1, result = '\0',currentIns = '\0';
		int count = 0;

		for(int i = 0; i < arr.size() - 1 && COUNTER < 65536; i+=2){

			ch = (Character)arr.get(i);
			ch1 = (Character)arr.get(i + 1);

			if(ch == '\n' || ch == ' '){
				i--;
				if(ch == '\n')showAndCalc();
				continue;
			}

			if((count > 0) && (currentIns == 'm' || currentIns == 'A' || currentIns 
== 's' ||
				currentIns == 'M' || currentIns == 'D' || currentIns == 'a' || 
currentIns == 'O')){

					if(count < 3){
						count++;
					if(ch1 == 'A')
						ch1 = '$';
					else if(ch1 == 'B')
						ch1 = '%';
					else if(ch1 == 'C')
						ch1 = '^';
					else if(ch1 == 'D')
						ch1 = '#';
					else if(ch1 == 'E')
						ch1 = '@';
					else if(ch1 == 'F')
						ch1 = '(';
					memory[COUNTER++] = ch1;
					}
					if(count > 2)
						count = 0;
					continue;
			}else if((count > 0) && (currentIns == 'I' || currentIns == '+' || 
currentIns == '-' ||
				currentIns == '*' || currentIns == '/' || currentIns == '&' || 
currentIns == '|')){

						if(count < 2){
							count++;
							if(ch1 == 'A')
								ch1 = '$';
							else if(ch1 == 'B')
								ch1 = '%';
							else if(ch1 == 'C')
								ch1 = '^';
							else if(ch1 == 'D')
								ch1 = '#';
							else if(ch1 == 'E')
								ch1 = '@';
							else if(ch1 == 'F')
								ch1 = '(';

							memory[COUNTER++] = ch1;

							continue;
						}
						if(count > 1){


							ch <<= 8;
							ch |= ch1;
							memory[COUNTER++] = ch;


							ch = (Character)arr.get(i +2);
							ch1 = (Character)arr.get(i + 3);

							ch <<= 8;
							ch |= ch1;
							i+=2;

							memory[COUNTER++] =ch;
							count = 0;
							continue;


						}
			}else if((count > 0) && (currentIns == 'Z' || currentIns == 'z' || 
currentIns == 'c' ||
				currentIns == 'b' || currentIns == 'j' || currentIns == 'C' || 
currentIns == 'T')){

						if(count == 2){
							ch <<= 8;
							ch|=ch1;
							memory[COUNTER++] = ch;

							count = 0;
							continue;
						}
						if(count == 1){
							ch <<= 8;
							ch|=ch1;
							memory[COUNTER++] = ch;

							count++;
							continue;
						}
			}else if((count > 0) && (currentIns == 'l' || currentIns == 'r' || 
currentIns == '<' ||
				currentIns == '>' || currentIns == 'i' || currentIns == 'd' || 
currentIns == 'p' ||
					currentIns == 'P')){
						if(ch1 == 'A')
							ch1 = '$';
						else if(ch1 == 'B')
							ch1 = '%';
						else if(ch1 == 'C')
							ch1 = '^';
						else if(ch1 == 'D')
							ch1 = '#';
						else if(ch1 == 'E')
							ch1 = '@';
						else if(ch1 == 'F')
							ch1 = '(';

					memory[COUNTER++] = ch1;
					count =0;
			}else if((count > 0) && (currentIns == 'L' || currentIns == 'S')){


					if(count < 2){
						count++;
						if(ch1 == 'A')
							ch1 = '$';
						else if(ch1 == 'B')
							ch1 = '%';
						else if(ch1 == 'C')
							ch1 = '^';
						else if(ch1 == 'D')
							ch1 = '#';
						else if(ch1 == 'E')
							ch1 = '@';
						else if(ch1 == 'F')
							ch1 = '(';
						memory[COUNTER++] = ch1;

						continue;
					}
					if(count == 3){
						ch <<= 8;
						ch |= ch1;

						memory[COUNTER++] = ch;


						count = 0;
					}
					if(count > 1){
						ch <<= 8;
						ch |= ch1;

						memory[COUNTER++] = ch;

						count++;

						continue;
					}

			}else{
				try{

					 result = convertTo(ch, ch1);
					 currentIns = result;
				}catch(InvalidInstructionSet e){
					System.out.println(e.getMessage());
					System.exit(1);
				}
				count++;
				memory[COUNTER++] = result;

			}

		}
		showAndCalc();

		assert COUNTER <= (32 * 1024) : "Trap: Code overflow the size of the 
program is too large to fit into code boundary.";

		System.out.println();
		SPReg.code.limit = COUNTER -1;
		SPReg.code.counter = 0;

		System.out.print("Code Base:		");
		binaryConverter(SPReg.code.base);
		System.out.println();
		System.out.print("Code Limit:		");
		binaryConverter(SPReg.code.limit);
		System.out.println();
		System.out.print("Code Counter:		");
		binaryConverter(SPReg.code.counter);

		System.out.println();
		SPReg.stack.base = SPReg.code.limit + 1;
		SPReg.stack.limit = SPReg.stack.base + 60;
		SPReg.stack.counter = SPReg.stack.base;
		System.out.println();
		System.out.print("Stack Base:		");
		binaryConverter(SPReg.stack.base);
		System.out.println();
		System.out.print("Stack Limit:		");
		binaryConverter(SPReg.stack.limit);
		System.out.println();
		System.out.print("Stack Counter:		");
		binaryConverter(SPReg.stack.counter);

		System.out.println();
		SPReg.data.base = SPReg.stack.limit + 1;
		SPReg.data.limit = 65535;
		System.out.println();
		System.out.print("Data Base:		");
		binaryConverter(SPReg.data.base);
		System.out.println();
		System.out.print("Data Limit:  		END OF Memory");

		System.out.println();
		System.out.println();
		System.out.println("The general purpose registers are all initialized to 
0.");
		showReg();
		initialized = true;


	}

	void binaryConverter(int number){
		long input = number;
		long	i = (number>32768) ? 65536:32768;
		 while(i!=0){
		       System.out.print((number&i)!=0 ? '1' : '0');
		       i=i>>1;
        }
	}

	boolean getProgramCounter(){
		return	SPReg.code.counter < SPReg.code.limit + 1? true : false;
	}

	String fetch()throws MemoryVoilationException{

		String str = "";

		if(initialized == false)
			throw new MemoryVoilationException("Trap: Access to memory without being 
initialized");


		assert (!(Character.isDigit(memory[SPReg.code.counter]))): "Some serious 
error.";

		System.out.print("Fetching the memory at location: ");
		 binaryConverter(SPReg.code.counter);
		 System.out.println();
		str += memory[SPReg.code.counter++];

		if(str.charAt(0) == 'S' || str.charAt(0) == 'L' || str.charAt(0) == 'I'  
|| str.charAt(0) == '-' ||
			(str.charAt(0) == '*') || str.charAt(0) == '+'||
			(str.charAt(0)  == '/')|| (str.charAt(0)== '&')|| (str.charAt(0) == 
'|')){
			str+= memory[SPReg.code.counter++];
			str+= memory[SPReg.code.counter++];
			str+= memory[SPReg.code.counter++];
		}else if(str.charAt(0) == 'l' || str.charAt(0) == 'r' || str.charAt(0) == 
'<' ||
			str.charAt(0) == '>' || str.charAt(0) == 'i' || str.charAt(0) == 'd' ||
				str.charAt(0) == 'p' || str.charAt(0) == 'P'){

				str+= memory[SPReg.code.counter++];

		}else{
			str+= memory[SPReg.code.counter++];
			str+= memory[SPReg.code.counter++];

		}

		return str;
	}

	String decode(String str){

		char ch;

		String[] ISAnames = {"MOV", "MOVI", "MOVL", "MOVS", "ADD", "ADDI", "SUB", 
"SUBI", "MUL", "MULI",
			"DIV", "DIVI", "AND", "ANDI", "OR", "ORI", "SHL", "SHR", "RTL", "RTR", 
"INC", "DEC", "PUSH",
			"POP","DUMP","DUMP", "DUMP", "NOOP","DUMP","DUMP", "BZ", "BNZ", "BC", 
"BS", "JMP","DUMP","DUMP",
			"DUMP","DUMP", "DUMP", "DUMP", "DUMP","DUMP", "DUMP", "CALL", "RETURN", 
"ACT", "END"};
		String[] GPRnames = {"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", 
"R9", "R10", "R11", "R12", "R13","R14", "R15"};
		String str1 = "";

		System.out.println("Decoding the instruction fetched in previous step.");


		ch = str.charAt(0);
		if(ch == 'F'){
			str1 += "END";
			return str1;
		}
		str1 += ISAnames[Integer.parseInt(convertBackTo(ch), 16)- 20] + "  ";

		if(ch == 'm' || ch == 'A' || ch == 's' || ch == 'M' || ch == 'D' || ch == 
'a' || ch == 'O'){

			str1 += GPRnames[Integer.parseInt(str.charAt(1) + "")];

			str1 += " " + GPRnames[Integer.parseInt(str.charAt(2) + "")];

		}else if(ch == 'I' || ch == '+' || ch == '-' ||
				ch == '*' || ch == '/' || ch == '&' || ch == '|'){

			if(Character.isLetter(str.charAt(1)))
				str1 += GPRnames[Integer.parseInt(str.charAt(1) + "", 16)] + " ";
			else
				str1 += GPRnames[Integer.parseInt(str.charAt(1) + "")] + " ";

			char temp = str.charAt(2);
			char temp2 =temp;
			temp2 >>= 8;
			temp <<= 8;
			temp >>= 8;
			char temp3 = str.charAt(3);
			char temp4 = temp3;
			temp4 >>= 8;
			temp3 <<= 8;
			temp3 >>= 8;

			str1 += " " + temp2 + temp + "" + temp4 + temp3;
		}else if((ch == 'Z' || ch == 'z' || ch == 'c' || ch == 'b'
				|| ch == 'j' || ch == 'C' || ch == 'T')){

			char temp = str.charAt(1);
			char temp2 =temp;
			temp2 >>= 8;
			temp <<= 8;
			temp >>= 8;
			char temp3 = str.charAt(2);
			char temp4 = temp3;
			temp4 >>= 8;
			temp3 <<= 8;
			temp3 >>= 8;
			str1 += " " + temp2 + temp + "" + temp4 + temp3;// + str.charAt(4) + "" 
+str.charAt(5));

		}else if((ch == 'L' || ch == 'S')){
			if(Character.isLetter(str.charAt(1)))
				str1 += GPRnames[Integer.parseInt(str.charAt(1) + "", 16)] + " ";
			else
				str1 += GPRnames[Integer.parseInt(str.charAt(1) + "")] + " ";
			char temp = str.charAt(2);
			char temp2 =temp;
			temp2 >>= 8;
			temp <<= 8;
			temp >>= 8;
			char temp3 = str.charAt(3);
			char temp4 = temp3;
			temp4 >>= 8;
			temp3 <<= 8;
			temp3 >>= 8;

			str1 += " " + temp2 + temp + "" + temp4 + temp3;// + str.charAt(4) + "" 
+str.charAt(5));
		}else if((ch == 'l' || ch == 'r' || ch == '<' ||
				ch == '>' || ch == 'i' || ch == 'd' || ch == 'p' ||ch == 'P')){
					if(Character.isLetter(str.charAt(1)))
						str1 += GPRnames[Integer.parseInt(str.charAt(1) + "", 16)] + " ";
					else
						str1 += GPRnames[Integer.parseInt(str.charAt(1) + "")] + " ";
		}

		return str1;


	}
	private static String[] explode(String str, String separators) {

   	  	 StringTokenizer tokenizer = new StringTokenizer(str, separators);
   	  	 int ct = tokenizer.countTokens();
         String[] tokens = new String[ct];

      	 for (int i = 0; i < ct; i++)
    	     tokens[i] = tokenizer.nextToken();
    	  return tokens;
   }

	private int  GPRegCode(String str){

		if(str.equals("R0"))
			return 0;
		else if(str.equals("R1"))
			return 1;
		else if(str.equals("R2"))
			return 2;
		else if(str.equals("R3"))
			return 3;
		else if(str.equals("R4"))
			return 4;
		else if(str.equals("R5"))
			return 5;
		else if(str.equals("R6"))
			return 6;
		else if(str.equals("R7"))
			return 7;
		else if(str.equals("R8"))
			return 8;
		else if(str.equals("R9"))
			return 9;
		else if(str.equals("R10"))
			return 10;
		else if(str.equals("R11"))
			return 11;
		else if(str.equals("R12"))
			return 12;
		else if(str.equals("R13"))
			return 13;
		else if(str.equals("R14"))
			return 14;
		else if(str.equals("R15"))
			return 15;
		else
			return -1;
	}
	private void showReg(){
		String[] GPRnames = {"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", 
"R9", "R10", "R11", "R12", "R13","R14", "R15"};
		System.out.println();
		for(int i = 0; i < 16; i++)
			System.out.println("			" + GPRnames[i] + ": 		" +GPReg[i]);
	}
	private void showStack(){
		System.out.println();
		for(int i = SPReg.stack.base;i < SPReg.stack.counter; i++){
			binaryConverter(i);
			System.out.println(":		" +(int)memory[i]);
		}
	}
	void execute(String str)throws MemoryVoilationException{

		System.out.println("Executing the instruction.");
		String[] arrOfIns;
		arrOfIns = explode(str, " ");
		int reg1, reg2;
		if(arrOfIns[0].equals("ADD")){
			reg1 = GPRegCode(arrOfIns[1]);
			reg2 = GPRegCode(arrOfIns[2]);
			GPReg[reg1] += GPReg[reg2];
			if(GPReg[reg1] >= 32767){
				SPReg.flag |= (1 << 3);
				GPReg[reg1] <<= 16;
				GPReg[reg1] >>= 16;
			}
			System.out.println("After the addition the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("MOV")){
			SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			reg2 = GPRegCode(arrOfIns[2]);
			GPReg[reg1] = GPReg[reg2];
			System.out.println("After moving, the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("SUB")){
			SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			reg2 = GPRegCode(arrOfIns[2]);
			GPReg[reg1] -= GPReg[reg2];
			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);

			System.out.println("After Subtraction, the registers are.");
			showReg();

		}else if(arrOfIns[0].equals("MUL")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			reg2 = GPRegCode(arrOfIns[2]);
			GPReg[reg1] *= GPReg[reg2];
			if(GPReg[reg1] >= 32768){
				SPReg.flag |= (1 << 3);
				GPReg[reg1] <<= 16;
				GPReg[reg1] >>= 16;
			}
			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);
			if(GPReg[reg1] < -32767){
				GPReg[reg1] = -32767;
				SPReg.flag |= (1 << 3);
			}
			System.out.println("After Multiplication, the registers are.");
			showReg();

		}else if(arrOfIns[0].equals("DIV")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			reg2 = GPRegCode(arrOfIns[2]);

			if(GPReg[reg2] == 0)
				throw new MemoryVoilationException("Fatal error: Attempt to divide by 
zero.");

			GPReg[reg1] /= GPReg[reg2];

			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);

			System.out.println("After Division, the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("AND")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			reg2 = GPRegCode(arrOfIns[2]);
			GPReg[reg1] =GPReg[reg1] & GPReg[reg2];
			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			System.out.println("After Anding, the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("OR")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			reg2 = GPRegCode(arrOfIns[2]);
			GPReg[reg1] = GPReg[reg1] | GPReg[reg2];

			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			System.out.println("After Oring, the registers are.");
			showReg();

		}else if(arrOfIns[0].equals("MOVI")){
					SPReg.flag = 0;
			int num;
			reg1 = GPRegCode(arrOfIns[1]);
			if(arrOfIns[2].charAt(0) >= '8'){
				String strT = Integer.toBinaryString(Integer.parseInt(arrOfIns[2], 16));
				char[] test = strT.toCharArray();
				for(int i = 0; i < test.length; i++)
					if(test[i] == '0')
						test[i] = '1';
					else
						test[i] = '0';
				strT = new String(test);
				num = Integer.parseInt(strT, 2);
				num = -num  - 1;
			}else
				 num = Integer.parseInt(arrOfIns[2], 16);
			if(num >32767)
				throw new MemoryVoilationException("An attempt to store value in memory 
greater than 16 bits.");

			GPReg[reg1]= num;
			System.out.println("After moving the immediate value, the registers 
are.");
			showReg();

		}else if(arrOfIns[0].equals("ADDI")){
					SPReg.flag = 0;
			int num;
			reg1 = GPRegCode(arrOfIns[1]);
			if(arrOfIns[2].charAt(0) >= '8'){
				String strT = Integer.toBinaryString(Integer.parseInt(arrOfIns[2], 16));
				char[] test = strT.toCharArray();
				for(int i = 0; i < test.length; i++)
					if(test[i] == '0')
						test[i] = '1';
					else
						test[i] = '0';
				strT = new String(test);
				num = Integer.parseInt(strT, 2);
				num = -num - 1;
				System.out.println(num);
			}else
				  num = Integer.parseInt(arrOfIns[2], 16);
			if(num + GPReg[reg1] >65535)
				throw new MemoryVoilationException("An attempt to store value in memory 
greater than 16 bits.");

			GPReg[reg1] += num;

			if(GPReg[reg1] > 32767){
				SPReg.flag |= (1 << 3);
				GPReg[reg1] &= 32767;
				GPReg[reg1] = -GPReg[reg1];
			}

			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);

			System.out.println("After the addition the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("SUBI")){
					SPReg.flag = 0;
			reg1 = GPRegCode(arrOfIns[1]);
			int num;
			if(arrOfIns[2].charAt(0) >= '8'){
							String strT = Integer.toBinaryString(Integer.parseInt(arrOfIns[2], 
16));
							char[] test = strT.toCharArray();
							for(int i = 0; i < test.length; i++)
								if(test[i] == '0')
									test[i] = '1';
								else
									test[i] = '0';
							strT = new String(test);
							num = Integer.parseInt(strT, 2);
							num = -num - 1;
							System.out.println(num);
			}else
				num = Integer.parseInt(arrOfIns[2], 16);

			GPReg[reg1] -= num;
			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);

			System.out.println("After Subtraction with immediate, the registers 
are.");
			showReg();
		}else if(arrOfIns[0].equals("MULI")){
					SPReg.flag = 0;
			int num;
			reg1 = GPRegCode(arrOfIns[1]);

						if(arrOfIns[2].charAt(0) >= '8'){
										String strT = Integer.toBinaryString(Integer.parseInt(arrOfIns[2], 
16));
										char[] test = strT.toCharArray();
										for(int i = 0; i < test.length; i++)
											if(test[i] == '0')
												test[i] = '1';
											else
												test[i] = '0';
										strT = new String(test);
										num = Integer.parseInt(strT, 2);
										num = -num - 1;
										System.out.println(num);
						}else
				num = Integer.parseInt(arrOfIns[2], 16);
			GPReg[reg1] *= num;
			if(GPReg[reg1] >= 65536){
				SPReg.flag |= (1 << 3);
				GPReg[reg1] <<= 16;
				GPReg[reg1] >>= 16;
			}
			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);
			System.out.println("After Multiplication with immediate, the registers 
are.");
			showReg();
		}else if(arrOfIns[0].equals("DIVI")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			int num;
						if(arrOfIns[2].charAt(0) >= '8'){
										String strT = Integer.toBinaryString(Integer.parseInt(arrOfIns[2], 
16));
										char[] test = strT.toCharArray();
										for(int i = 0; i < test.length; i++)
											if(test[i] == '0')
												test[i] = '1';
											else
												test[i] = '0';
										strT = new String(test);
										num = Integer.parseInt(strT, 2);
										num = -num - 1;
										System.out.println(num);
						}else
				num = Integer.parseInt(arrOfIns[2], 16);
			if(num == 0)
				throw new MemoryVoilationException("Fatal error: Attempt to divide by 
zero.");

			GPReg[reg1] /= num;

			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);

			System.out.println("After Division with immediate, the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("ANDI")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			int num;
						if(arrOfIns[2].charAt(0) >= '8'){
										String strT = Integer.toBinaryString(Integer.parseInt(arrOfIns[2], 
16));
										char[] test = strT.toCharArray();
										for(int i = 0; i < test.length; i++)
											if(test[i] == '0')
												test[i] = '1';
											else
												test[i] = '0';
										strT = new String(test);
										num = Integer.parseInt(strT, 2);
										num = -num - 1;
										System.out.println(num);
						}else
				num = Integer.parseInt(arrOfIns[2], 16);

			GPReg[reg1] =GPReg[reg1] & num;
			if(GPReg[reg1] == 0)
				SPReg.flag |= (1 << 1);

												if(GPReg[reg1] < 0)
					SPReg.flag |= (1 << 2);
			System.out.println("After Anding with immediate, the registers are.");
			showReg();
		}else if(arrOfIns[0].equals ("ORI")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			int num;
						if(arrOfIns[2].charAt(0) >= '8'){
										String strT = Integer.toBinaryString(Integer.parseInt(arrOfIns[2], 
16));
										char[] test = strT.toCharArray();
										for(int i = 0; i < test.length; i++)
											if(test[i] == '0')
												test[i] = '1';
											else
												test[i] = '0';
										strT = new String(test);
										num = Integer.parseInt(strT, 2);
										num = -num - 1;
										System.out.println(num);
						}else
				num = Integer.parseInt(arrOfIns[2], 16);

			GPReg[reg1] = GPReg[reg1] | num;

			if(GPReg[reg1] == 0)
					SPReg.flag |= (1 << 1);

								if(GPReg[reg1] < 0)
					SPReg.flag |= (1 << 2);
			System.out.println("After Oring, the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("BZ")){
			int num = Integer.parseInt(arrOfIns[1], 16);
			int test = SPReg.flag;
			test &= (1 << 1);
			if(test != 0){
				if((num + SPReg.code.base) <= SPReg.code.limit){
					SPReg.code.counter = SPReg.code.base + num;
					System.out.println("Flag Zero bit was on so jumped to the location " + 
SPReg.code.counter + " in PC.");
				}else
					throw new MemoryVoilationException("Trap: Branch to a out of bound 
memory code area.");
			}else
				System.out.println("Flag Zero bit was off so PC is in same location " + 
(SPReg.code.counter -3) + " in PC.");

			SPReg.flag = 0;
		}else if(arrOfIns[0].equals("BNZ")){
			int num = Integer.parseInt(arrOfIns[1], 16);
			int test = SPReg.flag;
			test &= (1 << 1);
			if(test == 0){
				if((num + SPReg.code.base) <= SPReg.code.limit)
					SPReg.code.counter = SPReg.code.base + num;
				else
					throw new MemoryVoilationException("Trap: Branch to a out of bound 
memory code area.");
			}else
				System.out.println("Flag Zero bit was on so PC is in same location " + 
(SPReg.code.counter -3) + " in PC.");
			SPReg.flag = 0;
		}else if(arrOfIns[0].equals("BC")){
			int num = Integer.parseInt(arrOfIns[1], 16);
			int test = SPReg.flag;
			test &= (1 << 0);
			if(test != 0){
				if((num + SPReg.code.base) <= SPReg.code.limit){
					SPReg.code.counter = SPReg.code.base + num;
					System.out.println("Flag carry bit was on so jumped to the location " + 
SPReg.code.counter + " in PC.");
				}else
					throw new MemoryVoilationException("Trap: Branch to a out of bound 
memory code area.");
			}else
				System.out.println("Flag carry bit was off so PC is in same location " + 
(SPReg.code.counter -3) + " in PC.");
		SPReg.flag = 0;
		}else if(arrOfIns[0].equals("BS")){
			int num = Integer.parseInt(arrOfIns[1], 16);
			int test = SPReg.flag;
			test &= (1 << 2);
			if(test != 0){
				if((num + SPReg.code.base) <= SPReg.code.limit){
					SPReg.code.counter = SPReg.code.base + num;
					System.out.println("Flag sign bit was on so jumped to the location " + 
SPReg.code.counter + " in PC.");
				}else
					throw new MemoryVoilationException("Trap: Branch to a out of bound 
memory code area.");
			}else
				System.out.println("Flag sign bit was off so jumped to the location " + 
SPReg.code.counter + " in PC.");
			SPReg.flag = 0;
		}else if(arrOfIns[0].equals("JMP")){
					SPReg.flag = 0;

			int num = Integer.parseInt(arrOfIns[1], 16);

			if((num + SPReg.code.base) <= SPReg.code.limit){
				SPReg.code.counter = SPReg.code.base + num;
				System.out.println("Jumped to the location " + SPReg.code.counter + " in 
PC.");
			}else
				throw new MemoryVoilationException("Trap: Branch to a out of bound 
memory code area.");
		}else if(arrOfIns[0].equals("CALL")){
			int num = Integer.parseInt(arrOfIns[1], 16);

			if((num + SPReg.code.base) <= SPReg.code.limit){
				memory[SPReg.stack.counter++]=(char)(SPReg.code.counter);
				SPReg.code.counter = SPReg.code.base + num;
			}else
				throw new MemoryVoilationException("Trap: Branch to a out of bound 
memory code area.");
			SPReg.flag = 0;
			System.out.println("Pushed the return value on stack and jumped to 
location " + SPReg.code.counter);
			showReg();
			showStack();

		}else if(arrOfIns[0].equals("MOVL")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			int num = Integer.parseInt(arrOfIns[2], 16);
			if(SPReg.data.base + num > 65535)
				throw new MemoryVoilationException("Trap: Out of reach memory offset for 
data.");

			GPReg[reg1] = memory[SPReg.data.base + num];

			System.out.println("After loading the value from memory into register, 
the registers are.");
			showReg();
		}else if(arrOfIns[0].equals("MOVS")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			int num = Integer.parseInt(arrOfIns[2], 16);
			if(SPReg.data.base + num > 65535)
				throw new MemoryVoilationException("Trap: Out of reach memory offset for 
data.");

			memory[SPReg.data.base + num] = (char)GPReg[reg1];
			System.out.println("After storing the value from memory into register, 
the registers are.");
			showReg();
			System.out.println("The data at offset " + (SPReg.data.base + num) + " is 
" +  (int)memory[SPReg.data.base + num] );
		}else if(arrOfIns[0].equals("SHL")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);

			if((GPReg[reg1] & (1 << 14)) != 0)
				SPReg.flag |= 1;
			System.out.println("Before left shift the register contents were.");
			System.out.println(arrOfIns[1] + ":			" + GPReg[reg1]);
			GPReg[reg1] <<=1;
			GPReg[reg1] &= (32767);
			System.out.println("After left shift the register contents are.");
			System.out.println(arrOfIns[1] + ":			" + GPReg[reg1]);

		}else if(arrOfIns[0].equals("SHR")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);

			System.out.println("Before right shift the register contents were.");
			System.out.println(arrOfIns[1] + ":			" + GPReg[reg1]);
			if((GPReg[reg1] & 1) != 0)
				SPReg.flag |= 1;
			GPReg[reg1] >>=1;

			System.out.println("After right shift the register contents are.");
			System.out.println(arrOfIns[1] + ":			" + GPReg[reg1]);

		}else if(arrOfIns[0].equals("RTL")){
			SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);

			System.out.println("Before Rotating left the register contents were.");
			System.out.println(arrOfIns[1] + ":			" + GPReg[reg1]);
			GPReg[reg1] <<=1;
			if((GPReg[reg1] & (1 << 15)) == 0)
				GPReg[reg1] &= 32766;
			else{
				SPReg.flag |= 1;
				GPReg[reg1] |=1;
				GPReg[reg1] &= 32767;
			}
			System.out.println("After Rotating left the register contents are.");
			System.out.println(arrOfIns[1] + ":			"+ GPReg[reg1]);
		}else if(arrOfIns[0].equals("RTR")){
			SPReg.flag = 0;

						reg1 = GPRegCode(arrOfIns[1]);

						System.out.println("Before Rotating right the register contents 
were.");
						System.out.println(arrOfIns[1] + ":			" + GPReg[reg1]);


						if((GPReg[reg1] & 1) == 0){
							GPReg[reg1] >>=1;
						}else{
							SPReg.flag |= 1;
							GPReg[reg1] >>=1;
							GPReg[reg1] |= 16384;
						}


						System.out.println("After Rotating right the register contents are.");
			System.out.println(arrOfIns[1] + ":			"+ GPReg[reg1]);
		}else if(arrOfIns[0].equals("INC")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			GPReg[reg1]++;
			if(GPReg[reg1] > 32767){
				SPReg.flag |= (1 << 3);
				SPReg.flag |= 1;
				GPReg[reg1] &= 32767;
			}

		}else if(arrOfIns[0].equals("DEC")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			GPReg[reg1]--;
			if(GPReg[reg1] < 0)
				SPReg.flag |= (1 << 2);

		}else if(arrOfIns[0].equals("PUSH")){
					SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			memory[SPReg.stack.counter++] = (char)GPReg[reg1];
			System.out.println("After pushing " + arrOfIns[1] + " on stack.");
			showStack();
		}else if(arrOfIns[0].equals("POP")){
			SPReg.flag = 0;

			reg1 = GPRegCode(arrOfIns[1]);
			GPReg[reg1] = memory[--SPReg.stack.counter];
			System.out.println("After popping " + arrOfIns[1] + " from stack.");
			showStack();
			showReg();
		}else if(arrOfIns[0].equals("RETURN")){
			SPReg.flag = 0;

			int PC = memory[--SPReg.stack.counter];
			SPReg.code.counter = PC;
			System.out.println("After popping PC from stack , returning to the 
original PC." + PC);

		}else if(arrOfIns[0].equals("NOOP")){
				SPReg.flag = 0;

			System.out.println("No operation Instruction.");
		}else if(arrOfIns[0].equals("END")){
			System.out.println("END OF PROGRAM.");
			System.exit(1);
		}
		showFlag();

	}

	void showFlag(){
		System.out.println("The flag register after execution of the 
instruction.");
		System.out.print("Flag: 		");
		binaryConverter(SPReg.flag);
	}

	void writeBack(){
	}

	private void showAndCalc(){

		int x = COUNTER;

		char test = memory[x-1];

		test >>= 10;
		test |= 0;
		boolean beenHere = false;
		if(memory[x-3] == 'Z' || memory[x-3] == 'z' || memory[x-3] == 'c' || 
memory[x-3] == 'C' ||
			memory[x-3] == 'j' )
			x -= 3;

			else{
		while(true)
		{
		if(test == 0){
		while(!(Character.isLetter(memory[x])) && memory[x]  != '-' &&
			(memory[x] != '*') && memory[x] != '+'&&
			(memory[x]!= '/')&& (memory[x] != '&')&& (memory[x]!= '|')&&

			(memory[x] != '<')&& (memory[x] != '>')&& (memory[x] != '~')&& (memory[x] 
!= '!')){
			x--;
			beenHere = true;
		}}else{
			x--;
		}
		test = memory[x];

		test >>= 10;
		test |= 0;

		if(beenHere)
		break;

		}}
		try{
			char currentIns = memory[x];
			String str = convertBackTo(memory[x]);
			System.out.println();
			binaryConverter(x);
			System.out.print(":		");
			System.out.println(str);

			if(currentIns == 'm' || currentIns == 'A' || currentIns == 's' ||
				currentIns == 'M' || currentIns == 'D' || currentIns == 'a' || 
currentIns == 'O'){

					for(int i = 0; i < 2; i++){
						binaryConverter(++x);
						System.out.print(":		");
						if(memory[x] == '$')
							memory[x] = 'A';
						else if(memory[x] == '%')
							memory[x] = 'B';
						else if(memory[x] == '^')
							memory[x] = 'C';
						else if(memory[x] == '#')
							memory[x] = 'D';
						else if(memory[x] == '@')
							memory[x] = 'E';
						else if(memory[x] == '(')
							memory[x] = 'F';
						System.out.println("0" + memory[x]);
					}
			}else if(currentIns == 'I' || currentIns == '+' || currentIns == '-' ||
				currentIns == '*' || currentIns == '/' || currentIns == '&' || 
currentIns == '|'){

						binaryConverter(++x);
						System.out.print(":		");
						System.out.print("0");
						if(memory[x] == '$')
													memory[x] = 'A';
												else if(memory[x] == '%')
													memory[x] = 'B';
												else if(memory[x] == '^')
													memory[x] = 'C';
												else if(memory[x] == '#')
													memory[x] = 'D';
												else if(memory[x] == '@')
													memory[x] = 'E';
												else if(memory[x] == '(')
							memory[x] = 'F';
						System.out.println(memory[x]);
						binaryConverter(++x);
						char test1 = memory[x];
						char test2 = test1;
						test2 >>= 8;
						test1 <<= 8;
						test1 >>= 8;

						System.out.print(":		");
						System.out.println(test2 + "" + test1);
						binaryConverter(++x);
						test1 = memory[x];
						test2 = test1;
						test2 >>= 8;
						test1 <<= 8;
						test1 >>= 8;

												System.out.print(":		");
						System.out.println(test2 + "" + test1);
			}else if(currentIns == 'Z' || currentIns == 'z' || currentIns == 'c' ||
				currentIns == 'b' || currentIns == 'j' || currentIns == 'C' || 
currentIns == 'T'){

						binaryConverter(++x);
						System.out.print(":		");
						test = memory[x];
						char test2 = test;
						test2 >>= 8;
						test <<= 8;
						test >>= 8;

						System.out.println(test2 + "" + test);
						binaryConverter(++x);
						System.out.print(":		");
						test = memory[x];
												 test2 = test;
												test2 >>= 8;
												test <<= 8;
						test >>= 8;

						System.out.println(test2 + "" + test);
			}else if((currentIns == 'L' || currentIns == 'S')){
						binaryConverter(++x);
						System.out.print(":		");
						if(memory[x] == '$')
													memory[x] = 'A';
												else if(memory[x] == '%')
													memory[x] = 'B';
												else if(memory[x] == '^')
													memory[x] = 'C';
												else if(memory[x] == '#')
													memory[x] = 'D';
												else if(memory[x] == '@')
													memory[x] = 'E';
												else if(memory[x] == '(')
							memory[x] = 'F';
						System.out.println("0" + memory[x]);

						binaryConverter(++x);
						System.out.print(":		");
						test = memory[x];
						char test2 = test;
						test2 >>= 8;
						test <<= 8;
						test >>= 8;

						System.out.println(test2 + "" + test);

						binaryConverter(++x);
						test = memory[x];
						test2 = test;
						test2 >>= 8;
						test <<= 8;
						test >>= 8;
						System.out.print(":		");
						System.out.println(test2 + "" + test);


			}else if((currentIns == 'l' || currentIns == 'r' || currentIns == '<' ||
				currentIns == '>' || currentIns == 'i' || currentIns == 'd' || 
currentIns == 'p' ||
					currentIns == 'P')){

						binaryConverter(++x);
						System.out.print(":		");
						if(memory[x] == '$')
													memory[x] = 'A';
												else if(memory[x] == '%')
													memory[x] = 'B';
												else if(memory[x] == '^')
													memory[x] = 'C';
												else if(memory[x] == '#')
													memory[x] = 'D';
												else if(memory[x] == '@')
													memory[x] = 'E';
												else if(memory[x] == '(')
							memory[x] = 'F';
						System.out.println("0" + memory[x]);
			}

		}catch(InvalidInstructionSet e){
			System.out.println(e.getMessage());
		}



	}

	private String convertBackTo(char ch){

		switch(ch){
			case 'm':
				return "14";
			case 'A':
				return "18";
			case 's':
				return "1A";
			case 'M':
				return "1C";
			case 'D':
				return "1E";
			case 'a':
				return "20";
			case 'O':
				return "22";
			case 'I':
				return "15";
			case '+':
				return "19";
			case '-':
				return "1B";
			case '*':
				return "1D";
			case '/':
				return "1F";
			case '&':
				return "21";
			case '|':
				return "23";
			case 'Z':
				return "32";
			case 'z':
				return "33";
			case 'c':
				return "34";
			case 'b':
				return "35";
			case 'j':
				return "36";
			case 'C':
				return "40";
			case 'T':
				return "51";
			case 'L':
				return "16";
			case 'S':
				return "17";
			case 'l':
				return "24";
			case 'r':
				return "25";
			case '<':
				return "26";
			case '>':
				return "27";
			case 'i':
				return "28";
			case 'd':
				return "29";
			case 'p':
				return "2A";
			case 'P':
				return "2B";
			case '~':
				return "41";
			case '!':
				return "2F";
			case 'F':
				return "FF";
			default:
				throw new InvalidInstructionSet("Error: The processing file has a 
instruction which the ISA doesnt understand. Oh lalala" + ch);
		}
	}
	private char convertTo(char ch, char ch1) throws InvalidInstructionSet{

		String str = "" + ch + ch1;

		if(str.equals("14"))
			return 'm';
		else if(str.equals("18"))
			return 'A';
		else if(str.equals("1A"))
			return 's';
		else if(str.equals("1C"))
			return 'M';
		else if(str.equals("1E"))
			return 'D';
		else if(str.equals("20"))
			return 'a';
		else if(str.equals("22"))
			return 'O';
		else if(str.equals("15"))
			return 'I';
		else if(str.equals("19"))
			return '+';
		else if(str.equals("1B"))
			return '-';
		else if(str.equals("1D"))
			return '*';
		else if(str.equals("1F"))
			return '/';
		else if(str.equals("21"))
			return '&';
		else if(str.equals("23"))
			return '|';
		else if(str.equals("32"))
			return 'Z';
		else if(str.equals("33"))
			return 'z';
		else if(str.equals("34"))
			return 'c';
		else if(str.equals("35"))
			return 'b';
		else if(str.equals("36"))
			return 'j';
		else if(str.equals("40"))
			return 'C';
		else if(str.equals("51"))
			return 'T';
		else if(str.equals("16"))
			return 'L';
		else if(str.equals("17"))
			return 'S';
		else if(str.equals("24"))
			return 'l';
		else if(str.equals("25"))
			return 'r';
		else if(str.equals("26"))
			return '<';
		else if(str.equals("27"))
			return '>';
		else if(str.equals("28"))
			return 'i';
		else if(str.equals("29"))
			return 'd';
		else if(str.equals("2A"))
			return 'p';
		else if(str.equals("2B"))
			return 'P';
		else if(str.equals("41"))
			return '~';
		else if(str.equals("2F"))
			return '!';
		else if(str.equals("FF"))
			return 'F';
		else
			throw new InvalidInstructionSet("Error: The processing file has a 
instructilolon which the ISA doesnt understand." + str);

	}

	 class SPRegisters{
		private int firstReg;
		private char flag;
		private int[] reserved;

		private Code code;
		private Data data;
		private STack stack;

		SPRegisters(){
			firstReg = 0;
			flag = 0;
			reserved = new int[6];
			code = new Code();
			data = new Data();
			stack = new STack();
		}

		void show(){
			System.out.println(code.limit);
		}


		private class Code{
			int base;
			int limit;
			int counter;


		}

		 private class STack{
			int base;
			int limit;
			int counter;
		}

		 private class Data {
			int base;
			int limit;
		}
	}

}

public class OSPhase1{
	static void introduction(){

		System.out.println(); 
		System.out.println();
		System.out.println();
		System.out.println();
	}

	static ArrayList<Character> readFromFile(String name, VMArchitecture VM) 
throws IllegalArgumentException{

		System.out.println("Opening the file " + name + " for input.");
		ArrayList<Character> temp = new ArrayList<Character>();

		try{
			TextIO.readFile(name);
		}catch(IllegalArgumentException e){
			throw new IllegalArgumentException("Cant open input file \"" + name + "\" 
for input.\n");
		}

		int noOfIns = TextIO.getlnInt();
		System.out.println();
		System.out.println("Accessing the file from harddrive..... ");
		System.out.println("Reading the contents of the file... ");
		System.out.println();

		System.out.println("Total no of instructions in the file: " + noOfIns);
		char ch;

		for(int i = 0; i < noOfIns; i++){
			do{
				ch = TextIO.getAnyChar();
				temp.add(ch);
			}while(ch != '\n');
		}


		System.out.println();

		System.out.println("The file consists of: ");

		for(int i = 0; i < temp.size(); i++)
			System.out.print((Character)temp.get(i));


		return temp;
	}

	public static void main(String[] arguments){

		String fileName, fetchedIns, decodedIns;
		ArrayList<Character> arrList;

		introduction();

		VMArchitecture VMArchitecture1 = new VMArchitecture();

		while(true){

			System.out.print("Please enter the name of the input processing file: ");
			fileName = TextIO.getln();

			try{
				arrList = readFromFile(fileName, VMArchitecture1);
				break;
			}catch(IllegalArgumentException e){
				System.out.println(e.getMessage());
			}
		}

		System.out.print("Press Enter to load the file into memory.......... ");
		TextIO.readStandardInput();
		TextIO.getAnyChar();

		System.out.println("Initializing the file into memory.............");
		VMArchitecture1.initialize(arrList);
		System.out.print("Initialization complete.......... ");
		System.out.println();
		System.out.println();

		System.out.println("Starting the machine execution cycle.");


		try{
			while(VMArchitecture1.getProgramCounter())
			{
				System.out.print("Press Enter to continue................");
				TextIO.getAnyChar();

				System.out.println();
				System.out.println();
				fetchedIns = VMArchitecture1.fetch();
				System.out.println("Fetched Instruction: 	" + fetchedIns);
				decodedIns = VMArchitecture1.decode(fetchedIns);
				System.out.println("Decoded Instruction: 	" + decodedIns);
				System.out.println();
				VMArchitecture1.execute(decodedIns);
				System.out.println();

			}
		}catch(VMArchitecture.MemoryVoilationException e){
			System.out.println(e.getMessage());
		}
	}
}

